package api

import (
	"a_plus_station/commons"
	"a_plus_station/dto_out"
	"a_plus_station/global"
	"a_plus_station/middlewares"
	"a_plus_station/models"
	"a_plus_station/tables"
	"a_plus_station/utils"
	"context"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"github.com/anaskhan96/go-password-encoder"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	jsoniter "github.com/json-iterator/go"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"io"
	"net/http"
	"time"
)

// 不要使用全局变量存储 state
// 改为每个请求单独生成并存储在会话中

var (
	googleOauthConfig = &oauth2.Config{
		ClientID:     "1091791221578-f7qjcdnaehp99vf2r5l28iq1u4mbgpok.apps.googleusercontent.com",
		ClientSecret: "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",
		RedirectURL:  "http://127.0.0.1:5000/api/v1/oAuth/callback", // 确保与注册路由一致
		Scopes:       []string{"openid", "profile", "email"},
		Endpoint:     google.Endpoint,
	}
)

type UserInfo struct {
	ID      string `json:"id"`
	Email   string `json:"email"`
	Name    string `json:"name"`
	Picture string `json:"picture"`
}

func generateStateToken() string {
	b := make([]byte, 32)
	if _, err := rand.Read(b); err != nil {
		return "fallback-state-" + fmt.Sprint(time.Now().UnixNano())
	}
	return base64.URLEncoding.EncodeToString(b)
}

func LoginHandler(c *gin.Context) {
	// 生成唯一 state 并存储到会话
	state := generateStateToken()
	session := sessions.Default(c)
	session.Set("oauth_state", state)

	// 调试：打印会话ID和state
	fmt.Printf("LoginHandler - 会话ID: %s, 设置state: %s\n", session.ID(), state)

	if err := session.Save(); err != nil {
		fmt.Printf("保存会话失败: %v\n", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法保存会话"})
		return
	}

	// 返回认证 URL 给前端
	url := googleOauthConfig.AuthCodeURL(state)
	c.JSON(http.StatusOK, gin.H{"redirect_url": url})
}

func CallbackHandler(c *gin.Context) {
	// 获取参数
	state := c.Query("state")
	code := c.Query("code")

	// 打印调试信息
	fmt.Printf("CallbackHandler - 接收参数: state=%s, code=%s\n", state, code)

	// 从会话中获取存储的 state
	session := sessions.Default(c)
	storedState := session.Get("oauth_state")

	// 调试：打印会话信息
	fmt.Printf("会话ID: %s\n", storedState)

	// 打印 Cookie 详情
	cookies := c.Request.Cookies()
	for _, cookie := range cookies {
		fmt.Printf("Cookie: %s=%s\n", cookie.Name, cookie.Value)
	}

	if storedState == nil {
		// 尝试从请求中获取更多信息
		cookies := c.Request.Header.Get("Cookie")
		fmt.Printf("请求Cookie: %s\n", cookies)

		c.JSON(http.StatusBadRequest, gin.H{"error": "会话中未找到 state"})
		return
	}

	// 验证 state
	if storedState.(string) != state {
		fmt.Printf("State 不匹配: 存储的=%s, 请求的=%s\n", storedState, state)
		c.JSON(http.StatusBadRequest, gin.H{
			"error":         "state 参数不匹配",
			"stored_state":  storedState,
			"request_state": state,
		})
		return
	}

	// 交换授权码获取令牌
	token, err := googleOauthConfig.Exchange(context.Background(), code)
	if err != nil {
		fmt.Printf("令牌交换失败: %v\n", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法获取令牌: " + err.Error()})
		return
	}

	// 存储令牌在会话中
	session.Set("token", token.AccessToken)
	if err := session.Save(); err != nil {
		fmt.Printf("保存会话失败: %v\n", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法保存会话: " + err.Error()})
		return
	}

	c.Redirect(http.StatusMovedPermanently, "http://127.0.0.1:8888/#/pc/account?oauth=true")
}

func UserHandler(c *gin.Context) {
	session := sessions.Default(c)
	token := session.Get("token")
	if token == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权"})
		return
	}

	// 使用令牌获取用户信息
	userInfo, err := getUserInfo(token.(string))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法获取用户信息: " + err.Error()})
		return
	}

	// todo 保存到后端, 然后返回
	var user tables.User
	var register bool
	result := global.DB.Where(tables.User{Email: userInfo.Email}).First(&user)
	if result.RowsAffected == 1 {
		register = true
	}

	firstName, lastName := utils.ParseName(userInfo.Name)

	googleUserInfo := dto_out.UserInfo{
		Email:     userInfo.Email,
		FirstName: firstName,
		LastName:  lastName,
		Mobile:    *user.Mobile,
		Address:   user.Address,
		ID:        user.ID,
	}

	// 生成token
	j := middlewares.NewJWT()
	claims := models.CustomClaims{
		ID: user.ID,
		StandardClaims: jwt.StandardClaims{ // 可选参数
			NotBefore: time.Now().Unix(),           // 签名的生效时间
			ExpiresAt: time.Now().Unix() + 60*60*8, // 八个小时过期
			Issuer:    commons.Issuer,
		},
	}
	myToken, err := j.CreateToken(claims)

	outputUserInfo := dto_out.UserTokenInfo{
		UserInfo: googleUserInfo,
		Token:    myToken,
	}

	if register {
		// 添加用户的信息 和颁发的 token
		c.JSON(http.StatusOK, gin.H{
			"msg":  "用户登陆成功",
			"data": outputUserInfo,
		})
		return
	}

	// 密码加密
	options := &password.Options{SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New}
	salt, encodedPwd := password.Encode("", options)
	user.Password = fmt.Sprintf("$%s$%s$%s", "pbkdf2-sha512", salt, encodedPwd)

	user.Email = googleUserInfo.Email
	user.FirstName = googleUserInfo.FirstName
	user.LastName = googleUserInfo.LastName

	// 创建用户
	tx := global.DB.Begin()
	result = tx.Create(&user) // 通过数据的指针来创建
	if result.Error != nil {
		//return nil,status.Errorf(codes.Internal,result.Error.Error()) // .Error()会帮我们转换成error
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "用户注册失败",
		})
		tx.Rollback()
		return
	}
	tx.Commit()

	// 添加用户的信息 和颁发的 token
	c.JSON(http.StatusOK, gin.H{
		"msg":  "用户登陆成功",
		"data": outputUserInfo,
	})
}

func LogoutHandler(c *gin.Context) {
	session := sessions.Default(c)
	session.Clear()
	session.Save()
	c.JSON(http.StatusOK, gin.H{"message": "已退出登录", "redirect": "/"})
}

func getUserInfo(accessToken string) (*UserInfo, error) {
	// 创建带超时的上下文 (5秒超时)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 创建自定义 Transport 支持代理
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment, // 自动读取环境变量中的代理设置
		// 可根据需要添加其他安全配置
		// TLSClientConfig: &tls.Config{...},
	}

	// 创建带自定义 Transport 的 HTTP 客户端
	client := &http.Client{
		Transport: transport,
		Timeout:   5 * time.Second, // 整个请求超时时间
	}

	// 创建请求对象
	req, err := http.NewRequestWithContext(ctx, "GET", "https://www.googleapis.com/oauth2/v2/userinfo", nil)
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+accessToken)

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 检查响应状态
	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body) // 尝试读取错误信息
		return nil, fmt.Errorf("API 返回错误状态: %s, 响应: %s", resp.Status, string(body))
	}

	// 解析响应数据
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %w", err)
	}

	var userInfo UserInfo
	if err := jsoniter.Unmarshal(body, &userInfo); err != nil {
		return nil, fmt.Errorf("JSON 解析失败: %w", err)
	}

	return &userInfo, nil
}

//set HTTP_PROXY=http://127.0.0.1:7897
//set HTTPS_PROXY=http://127.0.0.1:7897
